package cn.mrdjun.uid.starter.config;

import cn.mrdjun.uid.starter.constant.Mode;
import cn.mrdjun.uid.starter.worker.DatasourceWorkerIdAssigner;
import cn.mrdjun.uid.starter.worker.WorkerIdAssigner;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

/**
 * 线上环境依赖于数据库生成WorkId,用于自动生成其对应的WorkId以及避免重复，
 * Spring容器中必须存在SQLSessionFactory相关Bean，才能启用以下两种环境
 *
 * @author MrDJun 2021/5/6
 */
@Slf4j
@Configuration
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
@EnableConfigurationProperties(MybatisProperties.class)
@ConditionalOnProperty(value = "fun.uid.assigner-mode", havingValue = Mode.DB)
public class UidDatasourceAssignerConfigure {

    @Bean(name = "uidSqlSessionFactory")
    @ConditionalOnBean(DataSource.class)
    public SqlSessionFactory uidSqlSessionFactory(DataSource ds, MybatisProperties properties) throws Exception {
        SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(ds);
        // 解决 application.properties 中 配置mybatis.mapper-locations 失效的问题
        sqlSessionFactory.setMapperLocations((Resource[]) ArrayUtils.addAll(properties.resolveMapperLocations(),
                new PathMatchingResourcePatternResolver().getResources("classpath*:/META-INF/mapper/*.xml")));
        return sqlSessionFactory.getObject();
    }

    /**
     * 基于DB生成节点ID（主选）
     */
    @Bean
    @ConditionalOnBean(SqlSessionFactory.class)
    @ConditionalOnMissingBean(DatasourceWorkerIdAssigner.class)
    public WorkerIdAssigner disposableWorkerIdAssigner(SqlSessionFactory sqlSessionFactory) {
        log.info("WorkerIdAssigner turn on datasource");
        return new DatasourceWorkerIdAssigner(sqlSessionFactory);
    }
}